#include "FrameworkWorker.h"
#include "../Framework.h"
#include "../../Solution/Solution.h"
#include "../../Environment/Environment.h"
#include "../../Crossover/Crossover.h"
#include "../../Selection/Selection.h"
#include "../../Job/Crossover/CrossoverJob.h"

FrameworkWorker::FrameworkWorker(Framework *newFramework)
{
    framework = newFramework;
    exitSignal = false;
}

void FrameworkWorker::run()
{   
    while (!exitSignal) 
    {
        framework->completedEvaluateFitnessJobsMutex.acquire();
        if (framework->completedEvaluateFitnessJobs == framework->populationSize)
        {   
            framework->completedEvaluateFitnessJobs = 0;
            framework->completedEvaluateFitnessJobsMutex.release();
            
            for (unsigned int i = 0; i < framework->currentPopulation.size(); ++i)
                delete framework->currentPopulation[i];
            
            framework->newPopulationMutex.acquire();
            framework->currentPopulation = framework->newPopulation;
            framework->newPopulation.clear();
            framework->newPopulationMutex.release();
            
            //since we support fitnesses below 0, we need say that the worst fitness
            //is the most negative double in existance
            double thisGenerationMaxFitness = DBL_MAX * -1;
            double thisGenerationAvgFitness = 0.0;
            
            for (unsigned int i = 0; i < framework->currentPopulation.size(); ++i) 
            {
                double thisFitness = framework->currentPopulation[i]->getFitness();
                thisGenerationAvgFitness += thisFitness;
                thisGenerationMaxFitness = max(thisGenerationMaxFitness, thisFitness);
            }
            
		    thisGenerationAvgFitness /= framework->currentPopulation.size();
		    
            framework->historyMutex.acquire();
            ++framework->generationCount;
		    framework->topFitnessHistory.push_front(thisGenerationMaxFitness);
		    framework->avgFitnessHistory.push_front(thisGenerationAvgFitness);
		    framework->topFitnessHistory.pop_back();
		    framework->avgFitnessHistory.pop_back();
            framework->historyMutex.release();
	            
            framework->selector->prepare(framework->currentPopulation);
            
            // Move this inside the loop?
            framework->unassignedCrossoverJobsMutex.acquire();
            
//            cout << "Currentpopulation size: " << currentPopulation.size() << endl;
			for (unsigned int i = 0; i < framework->currentPopulation.size(); i += 2)
		    {
                Solution *parent1;
                Solution *parent2;
                
		        framework->selector->select(parent1, parent2);
                CrossoverJob *cJob = new CrossoverJob(parent1, parent2);
//                cout << "Crossover job generated." << endl;
                framework->unassignedCrossoverJobs.push_back(cJob);
		    }            
		            
            framework->unassignedCrossoverJobsMutex.release();
        }
        else
        {
            framework->completedEvaluateFitnessJobsMutex.release();
            ZThread::Thread::yield();
        }
        
//        cout << "just finished generation # " << generationCount << " of "
//             << targetGenerationCount << ". (flag: " << limitedRunFlag 
//             << ")" << endl;
//        
        if ((framework->generationCount > framework->targetGenerationCount) && framework->limitedRunFlag) {
            break;
        }
    }    
}

void FrameworkWorker::requestHalt()
{
    exitSignal = true;
}
